/* 
 * File:   Flob.h
 * Author: filipp
 *
 * Created on May 13, 2010, 7:18 PM
 */

#ifndef _FLOB_H
#define	_FLOB_H

#include "misc.h"
#include <string.h>
#include <iostream>
#include <SFML/System.hpp>

#define FLOB_DIVISOR 2.5f
#define FLOB_BORDER_BOUNCE 1.f

class Flob{
public:
////Accelerator////
	static void t_threadFunc(void* dat);	//this function will delete dat
	struct TF_DATA{
		enum TFTR{
			TF_NONE,
			TF_DIFF_DENS,
			TF_DIFF_VELX,
			TF_DIFF_VELY,
			TF_ADV_DENS,
			TF_ADV_VELX,
			TF_ADV_VELY,
			TF_ACC_VELX,
			TF_ACC_VELY,
			TF_PROJ1,
			TF_PROJ2,
			TF_PROJ3,
			TF_DISP_SCAN1,
			TF_DISP_SCAN2,
			TF_DISP_SCAN3,
			TF_DISP_GEN
		};
		TF_DATA(TFTR ftr=TF_NONE, Flob* mf=NULL, float t=0.f) : funcToRun(ftr),
			myFlob(mf), dt(t) {}
		TFTR funcToRun;
		Flob* myFlob;
		float dt;
	};
////IMPORTANT////
	Flob(float n, float d);
	~Flob();
	vec2i resize(vec2i sxy);
	vec2i getSize() const;
////SIMULATORS////
	void simDensStep(float dt);
	void simVelStep(float dt);
	void simFlStep(float dt);
	void simPhysStep(float dt);
////DRAWING FUNCTIONS//// assume opengl scaling is set up
	void drawDens(byte color);
	void drawVel();
	void drawSmart();
	void dbgPrintInfo(std::ostream& out);
////data information////
	void getDensData(float& avg, float& stdev) const;
	void getVelxData(float& avg, float& stdev) const;
	void getVelyData(float& avg, float& stdev) const;
	void getVelData(float& avg, float& stdev) const;
////headache relievers////
	float getVelx(vec2f pos) const;
	float getVely(vec2f pos) const;
	vec2f getVel(vec2f pos) const;
	float getDens(vec2f pos) const;

	void addDens(vec2f pos, float aDens);
	void setDens(vec2f pos, float sDens);

	void addDens(vec2i pos, float aDens);
	void addDens(size_t index, float aDens);
	void setDens(vec2i pos, float sDens);
	void setDens(size_t index, float sDens);

	void addAcc(vec2f pos, vec2f force);
	void addAcc(vec2i pos, vec2f force);
	void addAcc(size_t index, vec2f force);

	inline size_t IX(int x, int y) const;
	inline size_t IX(vec2i xy) const;
private:
////NO COPY////
	Flob(const Flob&);
	Flob& operator=(const Flob&);
////LINEAR SOLVER FUNC////
	void diffuseVal(int b, int iter, float rate, float* d, float* d0, float def=0);
	void advectVal(int b, float rate, float* d, float* d0, float def=0);
	void project(int iter, float dVel=0, float dDens=1, float dt=0);
	void projectThread(int iter, float dDens=1, float dt=0);
	void projectVelx();
	void projectVely();
	void setBnd(int b, float* x, float def=0);	//1=x, 2=y, 3=both, 0=neither

////NEATNESS FUNCTIONS////
	void simDiffAll(float dt);
	void simAdvAll(float dt);
////FOOKIN PRAWNS////
	float getVal(vec2f pos, float* d) const;
	float* velx;
	float* vely;
	float* velx0;
	float* vely0;
	float* accx;
	float* accy;
	float* dens;
	float* dens0;
	float* diverg;
	//float* curl;	//for future maybe
	vec2i sizexy;
	size_t size;
	bool inited;
	float Nvalue;
	float diff;

	sf::Thread sft_a;
	sf::Thread sft_b;
	sf::Thread sft_c;
	TF_DATA tf_a;
	TF_DATA tf_b;
	TF_DATA tf_c;


	//for drawing
	statisticTracker dTrack;
	statisticTracker vxTrack;
	statisticTracker vyTrack;
};

size_t Flob::IX(int x, int y) const{
	return y*sizexy.x + x;
}
size_t Flob::IX(vec2i xy) const{
	return xy.y*sizexy.x + xy.x;
}





#endif	/* _FLOB_H */

